#include "client.h"

void setEcho(bool enable) {
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    if (enable)
        tty.c_lflag |= ECHO;
    else
        tty.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &tty);
}

char *getPassword(const char *prompt) {
    printf("%s", prompt);
    setEcho(false);  // 关闭回显
    char *password = (char *)malloc(100);
    fgets(password, 100, stdin);
    setEcho(true);   // 恢复回显
    printf("\n");     // 因为关闭回显时换行符不显示，手动补一个
    return password;
}

// 登陆验证
int loginCheck(char *username, const int sockfd, char *passwd){

    // 创建TLV结构体
    tlvPacket_t tlv;

    // 用户验证
    while(1){

        // 获取用户名
        printf("请输入用户名: ");
        fflush(stdout);
        fgets(username, sizeof(username), stdin);

        // 去除最后一个换行符
        if(username[strlen(username)-1] == '\n'){
            username[strlen(username)-1] = 0;
        }

        // 用户验证, TLV发送用户名
        tlv.type = LOGIN;
        tlv.length = strlen(username);
        memcpy(tlv.value, username, tlv.length);
        send(sockfd, &tlv, sizeof(tlv.type)+sizeof(tlv.length)+
             tlv.length, MSG_NOSIGNAL);

        // 接收标志，判断用户是否已存在
        int userIsExist;
        int ret = recv(sockfd, &userIsExist, sizeof(int), MSG_WAITALL);
        if(ret == 0){
            printf("服务端已退出！\n");
            exit(1);
        }

        // 用户不存在
        if(userIsExist == 0){
            printf("用户不存在，是否创建新用户？是（y/Y），否（任意键）: ");
            char isCreate[4096] = {0};
            // 获取用户响应
            fgets(isCreate, sizeof(isCreate), stdin);

            // 去除最后一个换行符
            if(isCreate[strlen(isCreate)-1] == '\n'){
                isCreate[strlen(isCreate)-1] = 0;
            }

            // 创建新用户
            if(strcmp(isCreate, "y") == 0||strcmp(isCreate, "Y") == 0){
                // 发送TLV注册命令，和用户名
                tlv.type = REGISTER;
                send(sockfd, &tlv, sizeof(tlv.type)+sizeof(tlv.length)+
                     tlv.length, MSG_NOSIGNAL);

                // 接收盐值
                char plaintext[4096] = {0}; // 存储明文
                char ciphertext[4096] = {0}; // 存储密文
                char salt[4096] = {0};
                recv(sockfd, &tlv.type, sizeof(commandType_t), MSG_WAITALL);
                recv(sockfd, &tlv.length, sizeof(int), MSG_WAITALL);
                recv(sockfd, tlv.value, tlv.length, MSG_WAITALL);
                memcpy(salt, tlv.value, tlv.length);


                // 用户输入注册密码
                while(1){
                    char passwd1[4096] = {0};
                    char passwd2[4096] = {0};
                    char *tmp = getPassword("请输入密码：");
                    memcpy(passwd1, tmp, strlen(tmp));
                    free(tmp);
                    tmp = getPassword("请再次输入密码：");
                    memcpy(passwd2, tmp, strlen(tmp));
                    free(tmp);
                    if(strcmp(passwd1, passwd2) == 0){
                        // 密码一致，存储到明文
                        memcpy(plaintext, passwd1, strlen(passwd1));
                        break;
                    }
                    printf("两次密码不一致!\n");

                }

                // 生成并发送密文
                char *tmp = crypt(plaintext, salt);
                memcpy(ciphertext, tmp, strlen(tmp));
                tlv.type = REGISTER;
                tlv.length = strlen(ciphertext);
                memcpy(tlv.value, ciphertext, tlv.length);
                send(sockfd, &tlv, sizeof(tlv.type)+sizeof(tlv.length)+
                     tlv.length, MSG_NOSIGNAL);
                int registerTag;
                recv(sockfd, &registerTag, sizeof(int), MSG_WAITALL);
                if(registerTag == 1){
                    printf("注册成功！\n");
                    // 传出明文密码
                    memcpy(passwd, plaintext, strlen(plaintext));
                    return 0; // 注册成功，跳过密码验证
                }
                else{
                    printf("注册失败！\n");
                    exit(-1);
                }



            }

            // 不创建新用户，继续输入用户名
            else{
                continue;
            }

        }

        // 用户存在
        else{
            break;
        }
    }

    // 密码验证
    // 接收盐值
    char plaintext[4096] = {0}; // 存储明文
    char ciphertext[4096] = {0}; // 存储密文
    char salt[4096] = {0};
    recv(sockfd, &tlv.type, sizeof(commandType_t), MSG_WAITALL);
    recv(sockfd, &tlv.length, sizeof(int), MSG_WAITALL);
    recv(sockfd, tlv.value, tlv.length, MSG_WAITALL);
    memcpy(salt, tlv.value, tlv.length);

    // 用户输入密码
    while(1){

        // 获取密码明文
        char *tmp = getPassword("请输入密码：");
        memcpy(plaintext, tmp, strlen(tmp)+1);
        free(tmp);

        // 生成并发送密文
        tmp = crypt(plaintext, salt);
        memcpy(ciphertext, tmp, strlen(tmp)+1);
        memset(&tlv, 0, sizeof(tlv));
        tlv.type = LOGIN;
        tlv.length = strlen(ciphertext);
        memcpy(tlv.value, ciphertext, tlv.length);
        send(sockfd, &tlv, sizeof(tlv.type)+sizeof(tlv.length)+
             tlv.length, MSG_NOSIGNAL);

        int loginTag;
        recv(sockfd, &loginTag, sizeof(int), MSG_WAITALL);
        if(loginTag == 1){
            printf("登录成功！\n");

            // 传出明文密码
            memcpy(passwd, plaintext, strlen(plaintext));
            return 0; 
        }
        else{
            printf("登录失败！\n");
        }
    }
}

